#! /bin/sh
#
# Routine sanity checks for libpqxx source tree.
#
# An environment variable "srcdir" should hold the source directory.  It
# defaults to the current directory, but it needs to be set for out-of-tree
# builds.

set -e
set -u


SRCDIR="${srcdir:-.}"
PQXXVERSION="$($SRCDIR/tools/extract_version)"


# This version must be at the top of the NEWS file.
check_news_version() {
    if ! head -n1 $SRCDIR/NEWS | grep -q "^$PQXXVERSION\$"
    then
        cat <<EOF >&2
Version $PQXXVERSION is not at the top of NEWS.
EOF
        exit 1
    fi
}


# Count number of times header $1 is included from each of given input files.
# Output is lines of <filename>:<count>, one line per file, sorted.
count_includes() {
    local HEADER_NAME WS PAT
    HEADER_NAME="$1"
    shift
    WS="[[:space:]]*"
    PAT="^${WS}#${WS}include${WS}[<\"]$HEADER_NAME[>\"]"
    grep -c "$PAT" $* | sort
}


# Check that any includes of $1-pre.hxx are matched by $1-post.hxx ones.
match_pre_post_headers() {
    local NAME TEMPDIR PRE POST HEADERS
    NAME="$1"
    TEMPDIR="$(mktemp -d)"
    if test -z "$TEMPDIR"
    then
        echo >&2 "Could not create temporary directory."
        exit 1
    fi
    PRE="$TEMPDIR/pre"
    POST="$TEMPDIR/post"
    HEADERS=$(find include/pqxx/* -type f | grep -v '\.swp$')
    count_includes \
        $SRCDIR/NAME-pre.hxx $HEADERS >"$PRE"
    count_includes \
        $SRCDIR/NAME-post.hxx $HEADERS >"$POST"
    DIFF="$(diff "$PRE" "$POST")" || /bin/true
    rm -r -- "$TEMPDIR"
    if test -n "$DIFF"
    then
        cat <<EOF >&2
The number of inclusions of compiler-internal.post.hxx does not match the
number of inclusions of compiler-internal.pre.hxx:

$DIFF
EOF
        exit 1
    fi
}


# Any file that includes compiler-internal-pre.hxx must also include
# compiler-internal-post.hxx, and vice versa.
check_compiler_internal_headers() {
    match_pre_post_headers "pqxx/internal/compiler-internal"
    match_pre_post_headers "pqxx/internal/ignore-deprecated"
}


cpplint() {
    local cxxflags

    if which clang-tidy >/dev/null
    then
        if test -e compile_flags
        then
            cxxflags=$(cat compile_flags)
        else
            cxxflags=""
        fi

# TODO: Please, is there any way we can parallelise this?
# TODO: I'd like cppcoreguidelines-*, but it's a tsunami of false positives.
        clang-tidy \
            $(find $SRCDIR/src $SRCDIR/tools $SRCDIR/test -name \*.cxx) \
            --checks=abseil-*,boost-*, \
            -- \
            -I$SRCDIR/include -Iinclude $cxxflags
    fi
}


pylint() {
    local PYFILES="$SRCDIR/tools/*.py $SRCDIR/tools/splitconfig"
    echo "Skipping pocketlint; it's not up to date with Python3."
    # if which pocketlint >/dev/null
    # then
    # 	pocketlint $PYFILES
    # fi

    echo "Skipping flake8; it's not up to date with Python3."
    # if which flake8 >/dev/null
    # then
    # 	flake8 $PYFILES
    # fi
}


cpplint
pylint
check_news_version
check_compiler_internal_headers
